package net.melon.cata.manager;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

import javax.annotation.PostConstruct;

import net.esj.basic.dao.querybuilder.QueryBuilder;
import net.esj.basic.exception.MelonRuntimeException;
import net.esj.basic.service.impl.DefaultServiceImpl;
import net.esj.basic.utils.CollectionUtils;
import net.esj.basic.utils.Validators;
import net.melon.cata.manager.exception.OverMaxCountException;
import net.melon.cata.manager.id.ScaleIDGenerate;
import net.melon.cata.manager.id.ScaleIDGenerateFactory;
import net.melon.cata.pojo.Catalog;

public abstract class CatalogServiceImpl<T extends Catalog> extends DefaultServiceImpl implements
		CatalogService<T> {

	private Class<T> entityClass = (Class<T>) Catalog.class;
	
	@Override
	public List<T> getChildren(Serializable parentId) {
		QueryBuilder<T> qb = createQueryBuilder(entityClass);
		if(parentId!=null){
			qb.eq("parent.id", parentId);
		}else{
			qb.isNull("parent");
		}
		qb.OrderByAsc("id");
		List<T> list =  queryListByQueryBuilder(qb);
		for(T t : list){
			QueryBuilder<T> qb2 = createQueryBuilder(entityClass);
			qb2.eq("parent.id", t.getId());
			List<T> children = queryListByQueryBuilder(qb2);
			if(!CollectionUtils.isEmpty(children)){
				t.setHasChildren(true);
			}
			//t.setChildren(new HashSet<T>(children));
		}
		return list;
	}

	@Override
	public T save(T catalog) throws OverMaxCountException {
		if(catalog.getParent()!=null){
			if(Validators.isEmpty(catalog.getParent().getId())
					|| catalog.getParent().getId()==0){
				catalog.setParent(null);
			}
		}
		catalog.setId(generateId(catalog));
		super.save(catalog);
		return catalog;
	}

	@Override
	public T update(T catalog) {
		super.update(catalog);
		return catalog;
	}

	@Override
	public void delete(T catalog) {
		T persist = get(catalog.getId(), entityClass);
		if(persist.isDurable()){
			throw new MelonRuntimeException("catalog.cannot.delete");
		}
		super.delete(persist);
	}

	@Override
	public T get(Serializable id) {
		T t = get(id, entityClass);
		String name = t.getName();
		T p =(T) t.getParent();
		List<String> list = new ArrayList<String>();
		while(p!=null){
			list.add(p.getName());
			p = (T) p.getParent();
		}
		t.setFullName(list.toArray(new String[]{}),getNameSplitter());
		return t;
	}

	@PostConstruct
	protected void init(){
		entityClass = (Class<T>) ((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0];
	}
	
	protected String getNameSplitter(){
		return "";
	}
	
	protected abstract String getScaleType();
	
	protected Long generateMaxBrotherId(T me){
		QueryBuilder<T> qb = createQueryBuilder(entityClass);
		if(me.getParent()==null){
			qb.isNull("parent");
		}else{
			qb.eq("parent", me.getParent());
		}
		Object o = queryMaxByQueryBuilder(qb, "id");
		long id = 9;
		if(o instanceof Number){
			id = ((Number)o).longValue();
		}
		return id;
	}
	
	protected ScaleIDGenerate getScaleIdGenerate(){
		return ScaleIDGenerateFactory.get(getScaleType());
	}
	
	protected Long generateId(T me) throws OverMaxCountException{
		return getScaleIdGenerate().generateBrother(generateMaxBrotherId(me),me.getParent());
	}
	
}
